// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <gtest/gtest.h>
#include <climits>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cantor/parser/parser.h>
#include <cantor/utility/json_reader.h>
#include <tests/config.h>
#include <tests/paser/node_check.h>

int main(int argc, char *argv[]) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

namespace cantor::parser {
    class PragmaJson {
    public:
        static PragmaJson &instance() {
            static PragmaJson instance;
            return instance;
        }

        const nlohmann::ordered_json &json() const { return json_; }

    private:
        PragmaJson() {
            std::string json_path = turbo::str_cat(testing::test_root, "/data/pragma.json");
            auto rs = read_file(json_path);
            KCHECK(rs.ok());
            json_ = std::move(rs).value_or_die();
        }

        nlohmann::ordered_json json_;
    };


    void check_set_case(SqlParser *parser, const nlohmann::ordered_json &case_json) {
        check_parse(parser->error, case_json);
        ASSERT_EQ(parser->result.size(), 1);
        StmtNode *stmt = (StmtNode *) parser->result[0];
        auto &result = case_json["result"];
        check_stmt_node_info(stmt, result);
        auto *set = (PragmaSetStmt *) stmt;
        /// vars
        const auto &vars = result["vars"].get<std::vector<nlohmann::ordered_json> >();
        ASSERT_EQ(set->var_list.size(), vars.size());

        for (auto i = 0; i < set->var_list.size(); ++i) {
            check_var_assign(set->var_list[i], vars[i]);
        }
        std::cout << std::string(120, '/') << std::endl;
        std::cout << stmt->to_json().dump() << std::endl;
        std::cout << std::string(120, '/') << std::endl;
    }

    TEST(test_parser, autocommit1) {
        auto &json = PragmaJson::instance().json();
        auto cjson = json["autocommit1"];
        cantor::parser::SqlParser parser;
        std::string sql = cjson["sql"];
        parser.parse(sql);
        check_set_case(&parser, cjson);
    }

    TEST(test_parser, autocommit0) {
        auto &json = PragmaJson::instance().json();
        auto cjson = json["autocommit0"];
        cantor::parser::SqlParser parser;
        std::string sql = cjson["sql"];
        parser.parse(sql);
        check_set_case(&parser, cjson);
    }


    TEST(test_parser, set_kv) { {
            auto &json = PragmaJson::instance().json();
            auto cjson = json["set_kv"];
            cantor::parser::SqlParser parser;
            std::string sql = cjson["sql"];
            parser.parse(sql);
            check_set_case(&parser, cjson);
        }
        // test system variable with identifier prefix
        {
            auto &json = PragmaJson::instance().json();
            auto cjson = json["set_kv_prefix"];
            cantor::parser::SqlParser parser;
            std::string sql = cjson["sql"];
            parser.parse(sql);
            check_set_case(&parser, cjson);
        }
        // test user variable
        {
            auto &json = PragmaJson::instance().json();
            auto cjson = json["set_kv_user_var"];
            cantor::parser::SqlParser parser;
            std::string sql = cjson["sql"];
            parser.parse(sql);
            check_set_case(&parser, cjson);
        }
    }
} // namespace cantor::parser
